package com.zhou.project.configurations.security;

import com.zhou.project.components.base.result.ResultCode;
import com.zhou.project.components.base.result.ResultData;
import com.zhou.project.components.redis.RedisComponent;
import com.zhou.project.configurations.security.fifter.CertificationFilter;
import com.zhou.project.configurations.security.fifter.LoginFilter;
import com.zhou.project.configurations.security.jwt.JwtWebToken;
import com.zhou.project.modules.system.user.service.SysUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.authentication.configuration.EnableGlobalAuthentication;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.util.StringUtils;

/**
 * @author zhouhonggang
 * @version 1.0.0
 * @project spring-boot-project
 * @datetime 2021/9/24 14:42
 * @description: SpringSecurity安全配置
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private SysUserService sysUserService;
    @Autowired
    private JwtWebToken jwtWebToken;
    @Autowired
    private RedisComponent redisComponent;


    @Bean
    PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //是否支持跨域访问 b/s 前端+后台
        http.cors().disable();
        //远程站点伪造攻击（cookie） 现在开发的没有cookie
        http.csrf().disable();
        //请求认证
        http.authorizeRequests()
                //执行指定的资源
                .antMatchers("/swagger-ui/**").permitAll()
                .antMatchers("/swagger-resources/**").permitAll()
                .antMatchers("/api/v2/**").permitAll()
                .antMatchers("/v3/api-docs/**").permitAll()
                //指定模块放行
                .antMatchers(HttpMethod.POST,"/circleGroup/**").permitAll()
                //其他资源一律需要认证授权
                .anyRequest().authenticated();
        /**
         * spring security 会话管理
         * SessionCreationPolicy.ALWAYS         一直创建HttpSession
         * SessionCreationPolicy.NEVER          Spring Security不会创建HttpSession 但如果他已经存在则使用httpSession
         * SessionCreationPolicy.IF_REQUIRED    Spring Security只会在需要时创建一个HttpSession
         * SessionCreationPolicy.STATELESS      Spring Security永远不会创建HttpSession,他不会使用HttpSession来获取SecurityContext
         */
        http.sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        //绑定登录过滤器，注入认证管理器
        http
            .addFilter( new LoginFilter(authenticationManager(), jwtWebToken, redisComponent))
            .addFilter( new CertificationFilter(authenticationManager(), jwtWebToken, redisComponent));
            //放行所有请求无需登陆认证
//            .antMatchers("/**").permitAll();
        http.exceptionHandling()
            //重写403 未认证
            .authenticationEntryPoint((request, response, exception) ->{
                ResultData.response(response,ResultData.failure(ResultCode.USER_NOT_LOGIN));
            });
        //退出登录
        http.logout()
                .logoutSuccessHandler((request,response,exception)->{
                    //1.删除token
                    //redis token
                   String authorization= request.getHeader(jwtWebToken.getHeader());
                   if (StringUtils.hasLength(authorization) && authorization.startsWith(jwtWebToken.getPrefix()))
                   {
                       //截取token
                       String token=authorization.substring(jwtWebToken.getPrefix().length());
                       redisComponent.del(token);

                   }
                    //2.返回响应
                   ResultData.response(response,ResultData.success(ResultCode.USER_LOGOUT_SUCCESS));
                });
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //内存中模拟登陆账号密码及角色相关信息
//        auth
//            .inMemoryAuthentication()
//            .withUser("admin").password("$2a$10$dYMAsJsG5dAUdAAzUFFV3Ok.tB117Zei6h51DjbGHU/NSy/F7YMey").roles("ADMIN")
//            .and()
//            .withUser("guest").password("$2a$10$lFPAnarRuGP6hqVY.Jzwy.6F/xP6bVhJujJdRWWsiAPUNKSeB4gRC").roles("USER");
//            auth
//                .userDetailsService(sysUserService)
//                .passwordEncoder(passwordEncoder());
//        System.out.println(passwordEncoder().encode("123456"));

            auth
                .authenticationProvider(daoAuthenticationProvider());


    }

    private DaoAuthenticationProvider daoAuthenticationProvider()
    {
        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
        provider.setHideUserNotFoundExceptions(false);
        provider.setUserDetailsService(sysUserService);
        provider.setPasswordEncoder(passwordEncoder());
        return provider;
    }

}
